package com.merry.sb.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;

import java.util.HashMap;

/**
 * @author zouyb
 * redis的常见命令的jedis实现。
 * 在这个类中可以看见，在redis的常用命令中，jedis的使用都和redis的命令保持高度一致性。
 * jedis只有两个方法与redis的命令有点出入。就是【jedis订阅频道】和【jedis退订频道】
 */
public class JedisDemo {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        JedisDemo jedisDemo = new JedisDemo();
        jedisDemo.dealRedisString(jedis);
    }


    /**
     * redis处理字符串类型的jedis代码实现。
     *      set：设置键的值。【set k1 v1】
     *      get：获取键的值。【get key】
     *      incr：将键的整数值加1。（仅限于整数）【incr key】
     *      decr：将键的整数值减1。（仅限于整数）【decr key】
     *      incrby：同上，只是需要自己设置步数。【incrby key 2】
     *      decrby：同上。【decrby key 2】
     *      mset：同时设置多个键值对。【mset k1 v1 k2 v2】
     *      mget：同时获取多个键值对。【mget k1 k2】
     *      setnx：只有在键不存在时，才设置，nx代表“set if not exists”。【setnx k1 v1】
     *      setex：设置键的值，并且设置过期时间。【setex k1 10 v1】
     *      getset：将键的值设置为新值，并返回旧的值。【getset k1 newv1】
     *
     * @param jedis
     */
    private void dealRedisString(Jedis jedis) {
        jedis.set("k1", "v1");
        jedis.get("k1");
        jedis.incr("k1");
        jedis.decr("k1");
        jedis.incrBy("k1", 2);
        jedis.decrBy("k1", 2);
        jedis.mset("k1", "v1", "k2", "v2");
        jedis.mget("k1", "k2");
        jedis.setnx("k1", "v1");
        jedis.setex("k1", 10, "v1");
        jedis.getSet("k1", "v1");
    }

    /**
     * redis处理哈希类型的jedis代码实现
     *      hset：设置哈希字段的值。【hset k1 field value】。k1找到对应的hash，filed就是当前value的key。
     *      hget：获取哈希字段的值。【hget k1 field】
     *      hgetall：获取哈希表中所有字段和值。【hgetall k1】
     *      hdel：删除一个或多个哈希字段。【hdel k1 field1 field2】
     *      hexists：检查哈希字段是否存在。【hexists k1 field】
     *      hincrby：为哈希表中的字段加上指定的增量。【hincrby key field 2】
     *      hsetnx：只有字段不存在时，才设置哈希字段的值。【hsetnx key field value】
     *
     * @param jedis
     */
    private void dealRedisHash(Jedis jedis) {
        jedis.hset("k1", "field", "value");
        jedis.hget("k1", "field");
        jedis.hgetAll("k1");
        jedis.hdel("k1", "field", "field1");
        jedis.hexists("k1", "field");
        jedis.hincrBy("k1", "field", 2);
        jedis.hsetnx("k1", "field", "value");
    }

    /**
     * redis处理列表类型的jedis代码实现
     *      lpush：在列表头部插入一个或多个值。【lpush k1 v1 v2】
     *      rpush：在列表尾部插入一个或多个值。【rpush k1 v1 v2】
     *      lpop：移除并返回列表的头元素。【lpop k1】
     *      rpop：移除并返回列表的尾元素。【rpop k1】
     *      lrange：获取列表中指定范围的元素，索引从0开始，负索引表示从列表尾部开始。【lrange k1 0 10】
     *      llen：获取列表的长度。【llen k1】
     *      lrem：根据参数count的值，移除列表中与参数value相等的元素。【lrem k1 c1 v1】。
     *          c1=0，表示移除列表中所有的v1。c1>0，表示从右边开始，移除c1个v1。c1<0，与c1>0相反。
     *
     * @param jedis
     */
    private void dealRedisLists(Jedis jedis) {
        jedis.lpush("k1", "v1", "v2");
        jedis.rpush("k1", "v1", "v2");
        jedis.lpop("k1");
        jedis.rpop("k1");
        jedis.lrange("k1", 0, 10);
        jedis.llen("k1");
        jedis.lrem("k1", 0, "v1");
    }

    /**
     * redis处理集合类型的jedis代码实现
     *      sadd：向集合中添加一个或多个成员。【sadd k1 v1 v2】
     *      srem：移除集合中的一个或多个成员。【srem k1 v1 v2】
     *      smembers：返回集合中的所有成员。【smembers k1】
     *      sIsMember：检查某个值是否是集合的成员。【sismember k1 v1】
     *      scard：获取集合中的成员数。【scard k1】
     *      sunion：返回给定集合的并集。【sunion k1 k2】
     *      sinter：返回给定集合的并集。【sinter k1 k2】
     *      sdiff：返回第一个集合与其他集合的差集。【soff k1 k2】
     *
     * @param jedis
     */
    private void dealRedisSets(Jedis jedis) {
        jedis.sadd("k1", "v1", "v2");
        jedis.srem("k1", "v1", "v2");
        jedis.smembers("k1");
        jedis.sismember("k1", "v1");
        jedis.scard("k1");
        jedis.sunion("k1", "k2");
        jedis.sinter("k1", "k2");
        jedis.sdiff("k1", "k2");
    }

    /**
     * redis处理有序集合类型的jedis代码实现
     *      zadd：向有序集合中添加一个或多个成员。或者更新已经存在成员的分数。【zadd k1 s1 v1 s2 v2】。s1就是v1的分数，排序就是按照分数来排序的。
     *      zrange：返回有序集合中指定区间内的成员，默认按照从小到大排序。【zrange key 0 10】
     *      zrem：移除有序集合中的一个或多个成员。【zrem k1 v1 v2】
     *      zscore：返回有序集合中指定成员的分数。【zscore k1 v1】
     *      zrangebyscore：返回有序集合中指定分数区间内的成员。【zrangebyscore k1 min max】
     *      zcount：返回有序集合中指定分区区间内成员数量。【zcount k1 min max】
     *
     * @param jedis
     */
    private void dealRedisZSets(Jedis jedis) {
        jedis.zadd("k1", 12.00, "v1");
        HashMap<String, Double> map = new HashMap<>();
        map.put("v1", 12.12);
        map.put("v2", 22.22);
        jedis.zadd("k1", map);
        jedis.zrange("k1", 0, 10);
        jedis.zrem("k1", "v1", "v2");
        jedis.zrangeByScore("k1", 10.00, 30.00);
        jedis.zcount("k1", 10.00, 30.00);
    }

    /**
     * redis处理发布订阅类型的jedis代码实现
     *      publish：将消息发送到指定的频道。【publish channel message】
     *      subscribe：订阅一个或多个频道。【subscribe channel1 channel2】
     *      unsubscribe：退订一个或多个频道。【unsubscribe channel1 channel2】
     *
     * @param jedis
     */
    private void dealRedisPubSub(Jedis jedis) {
        jedis.publish("c1", "这是一个消息1");
        //相当于这个订阅器订阅了c1、c2两个频道。
        jedis.subscribe(new RedisSubscriber(), "c1", "c2");
        //当前订阅器退订了c1、c2两个频道。
        new RedisSubscriber().unsubscribe("c1", "c2");
    }

    /**
     * redis处理键操作的jedis代码实现
     *      del：删除一个或多个键。 【del key1 key2】
     *      exists：检查一个键是否存在。 【exists key】
     *      expire：设置键的过期时间。【expire key 10】
     *      ttl：获取键的剩余过期时间，如果键不存在则返回-2，如果键没有设置过期时间则返回-1。【ttl key】
     *      type：获取键的存储类型。【type key】
     *
     * @param jedis
     */
    private void dealRedisKey(Jedis jedis) {
        jedis.del("k1", "k2");
        jedis.exists("k1");
        jedis.expire("k1", 10);
        jedis.ttl("k1");
        jedis.type("k1");
    }

    /**
     * redis处理一般命令的jedis代码实现
     *      ping：检测服务器是否在运行。
     *      select 1：选择数据库，redis默认有16个数据库（0-15）。
     *      flushdb：清空当前数据库中的所有键。
     *      flushall：清空所有数据库中的所有键。
     *
     * @param jedis
     */
    private void dealRedisCommon(Jedis jedis) {
        jedis.ping();
        jedis.select(1);
        jedis.flushDB();
        jedis.flushAll();
    }


    /**
     * redis的订阅器。
     * 这个就相当于是：你要告诉redis，你收到消息之后打算怎么处理（onMessage）、订阅成功之后怎么处理（onSubscribe）、退订了怎么处理（onUnsubscribe）。
     */
    class RedisSubscriber extends JedisPubSub {

        @Override
        public void onMessage(String channel, String message) {
            System.out.println("Received Message: " + message + " from channel: " + channel);
        }

        @Override
        public void onSubscribe(String channel, int subscribedChannels) {
            System.out.println("Subscribed to channel: " + channel + ". Now subscribed to " + subscribedChannels + " channels.");
        }

        @Override
        public void onUnsubscribe(String channel, int subscribedChannels) {
            System.out.println("Unsubscribed from channel: " + channel + ". Now subscribed to " + subscribedChannels + " channels.");
        }
    }
}
